/**
******************************************************************************
* @file    usbd_hid_core.c
* @author  MCD Application Team
* @version V1.1.0
* @date    19-March-2012
* @brief   This file provides the HID core functions.
*
* @verbatim
*      
*          ===================================================================      
*                                HID Class  Description
*          =================================================================== 
*           This module manages the HID class V1.11 following the "Device Class Definition
*           for Human Interface Devices (HID) Version 1.11 Jun 27, 2001".
*           This driver implements the following aspects of the specification:
*             - The Boot Interface Subclass
*             - The Mouse protocol
*             - Usage Page : Generic Desktop
*             - Usage : Joystick)
*             - Collection : Application 
*      
* @note     In HS mode and when the DMA is used, all variables and data structures
*           dealing with the DMA during the transaction process should be 32-bit aligned.
*           
*      
*  @endverbatim
*
******************************************************************************
* @attention
*
* <h2><center>&copy; COPYRIGHT 2012 STMicroelectronics</center></h2>
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
*        http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software 
* distributed under the License is distributed on an "AS IS" BASIS, 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/ 

/* Includes ------------------------------------------------------------------*/
#include "usbd_hid_core.h"
#include "usbd_req.h"
#include "usbd_desc.h"
#include <stdio.h>


#ifndef	_countof
#define _countof(a)			(sizeof(a) / sizeof(a[0]))
#endif


#define USBD_HID_DESCRIPTOR_TYPE		0x21
#define USBD_HID_REPORT_DESC			0x22
#define USBD_HID_REQ_SET_PROTOCOL		0x0B
#define USBD_HID_REQ_GET_PROTOCOL		0x03
#define USBD_HID_REQ_SET_IDLE			0x0A
#define USBD_HID_REQ_GET_IDLE			0x02
#define USBD_HID_REQ_SET_REPORT			0x09
#define USBD_HID_REQ_GET_REPORT			0x01


USBD_HID_GETREPORT USBD_HID_GetReport_cb = NULL;
USBD_HID_ENDOFSEND USBD_HID_EndOfSend_cb = NULL;


static uint8_t USBD_HID_Init(void *pdev, uint8_t cfgidx);
static uint8_t USBD_HID_DeInit(void *pdev, uint8_t cfgidx);
static uint8_t USBD_HID_Setup(void *pdev, USB_SETUP_REQ *req);
static uint8_t USBD_HID_DataIn(void *pdev, uint8_t epnum);
static uint8_t USBD_HID_DataOut(void *pdev, uint8_t epnum);
static uint8_t *USBD_HID_GetCfgDesc(uint8_t speed, uint16_t *length);
USBD_Class_cb_TypeDef USBD_HID_cb =
{
	USBD_HID_Init,
	USBD_HID_DeInit,
	USBD_HID_Setup,
	NULL, /* EP0_TxSent */
	NULL, /* EP0_RxReady */
	USBD_HID_DataIn, /* DataIn */
	USBD_HID_DataOut, /* DataOut */
	NULL, /* SOF */
	NULL, /* IsoINIncomplete */
	NULL, /* IsoOUTIncomplete */
	USBD_HID_GetCfgDesc,
#ifdef	USB_SUPPORT_USER_STRING_DESC
	USBD_USR_USRStringDesc,
#endif
};
static uint8_t HID_RxBuffer[HID_OUT_PACKET_SIZE] = {0,};


//////////////////////////////////////////////////////////////
//			 bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
// Byte 00 : <-------------------------------->  InRg  TipSW
// Byte 01 :                      ID
// Byte 02 :					 MSB X
// Byte 03 :					 LSB X
// Byte 04 :					 MSB Y
// Byte 05 :					 LSB Y
#define MULTITOUCH_COLLECTION									\
	0xa1, 0x02, 			/* COLLECTION (Logical)           */\
	0x05, 0x0d, 			/*   USAGE_PAGE (Digitizers)      */\
	0x09, 0x42, 			/*   USAGE (Tip Switch)           */\
	0x15, 0x00, 			/*   LOGICAL_MINIMUM (0)          */\
	0x25, 0x01, 			/*   LOGICAL_MAXIMUM (1)          */\
	0x75, 0x01, 			/*   REPORT_SIZE (1)              */\
	0x95, 0x01, 			/*   REPORT_COUNT (1)             */\
	0x81, 0x02, 			/*   INPUT (Data,Var,Abs)         */\
	0x09, 0x32, 			/*   USAGE (In Range)             */\
	0x81, 0x02, 			/*   INPUT (Data,Var,Abs)         */\
	0x95, 0x06, 			/*   REPORT_COUNT (6)             */\
	0x81, 0x03, 			/*   INPUT (Cnst,Ary,Abs)         */\
	0x75, 0x08, 			/*   REPORT_SIZE (8)              */\
	0x09, 0x51, 			/*   USAGE (Contact Identifier)   */\
	0x95, 0x01, 			/*   REPORT_COUNT (1)             */\
	0x81, 0x02, 			/*   INPUT (Data,Var,Abs)         */\
	0x05, 0x01, 			/*   USAGE_PAGE (Generic Desktop) */\
	0x26, 0xff, 0x7f,		/*   LOGICAL_MAXIMUM (32767)      */\
	0x75, 0x10,				/*   REPORT_SIZE (16)             */\
	0x55, 0x00,				/*   UNIT_EXPONENT (0)            */\
	0x65, 0x00,				/*   UNIT (None)                  */\
	0x35, 0x00,				/*   PHYSICAL_MINIMUM (0)         */\
	0x46, 0x00, 0x00,		/*   PHYSICAL_MAXIMUM (0)         */\
	0x09, 0x30,				/*   USAGE (X)                    */\
	0x81, 0x02,				/*   INPUT (Data,Var,Abs)         */\
	0x09, 0x31,				/*   USAGE (Y)                    */\
	0x81, 0x02,				/*   INPUT (Data,Var,Abs)         */\
	0xc0,					/* END_COLLECTION                 */

static uint8_t ReportDesc_Input[] =
{
#if	defined(USE_RELMOUSE)
	//////////////////////////////////////////////////////////////
	//			 bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
	// Byte 00 :				Report ID = 0x12
	// Byte 01 : <-------------------------->  Btn3  Btn2  Btn1
	// Byte 02 :					   X
	// Byte 03 :					   Y
	// Byte 04 :				  Delta Wheel
	// Btn3(MK_MBUTTON), Btn2(MK_RBUTTON), Btn1(MK_LBUTTON)
	//////////////////////////////////////////////////////////////
	0x05, 0x01, 						// USAGE_PAGE (Generic Desktop)
	0x09, 0x02, 						// USAGE (Mouse)
	0xa1, 0x01, 						// COLLECTION (Application)
	0x85, REPORTID_RELMOUSE,			//	 REPORT_ID (Relative Mouse)
	0x09, 0x01, 						//	 USAGE (Pointer)
	0xa1, 0x00, 						//	 COLLECTION (Physical)
	0x05, 0x09, 						//	   USAGE_PAGE (Button)
	0x19, 0x01, 						//	   USAGE_MINIMUM (Button 1)
	0x29, 0x03, 						//	   USAGE_MAXIMUM (Button 3)
	0x15, 0x00, 						//	   LOGICAL_MINIMUM (0)
	0x25, 0x01, 						//	   LOGICAL_MAXIMUM (1)
	0x75, 0x01, 						//	   REPORT_SIZE (1)
	0x95, 0x03, 						//	   REPORT_COUNT (3)
	0x81, 0x02, 						//	   INPUT (Data,Var,Abs)
	0x95, 0x05, 						//	   REPORT_COUNT (5)
	0x81, 0x03, 						//	   INPUT (Cnst,Var,Abs)
	0x05, 0x01, 						//	   USAGE_PAGE (Generic Desktop)
	0x09, 0x30, 						//	   USAGE (X)
	0x09, 0x31, 						//	   USAGE (Y)
	0x15, 0x81, 						//	   LOGICAL_MINIMUM (-127)
	0x25, 0x7f, 						//	   LOGICAL_MAXIMUM (127)
	0x75, 0x08, 						//	   REPORT_SIZE (8)
	0x95, 0x02, 						//	   REPORT_COUNT (2)
	0x81, 0x06, 						//	   INPUT (Data,Var,Rel)
	0x09, 0x38, 						//	   USAGE (WHEEL)
	0x75, 0x08, 						//	   REPORT_SIZE (8)
	0x95, 0x01, 						//	   REPORT_COUNT (1)
	0x15, 0x81, 						//	   LOGICAL_MINIMUM (-127)
	0x25, 0x7f, 						//	   LOGICAL_MAXIMUM (127)
	0x81, 0x06, 						//	   INPUT (Data,Var,Rel)

	0x95, 0x05,							//	   REPORT_COUNT (5)
	0x81, 0x03, 						//	   INPUT (Cnst,Var,Abs)

	0xc0,								//	 END_COLLECTION
	0xc0,								// END_COLLECTION
#endif	//USE_RELMOUSE

#if	defined(USE_ABSMOUSE)
	//////////////////////////////////////////////////////////////
	//			 bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
	// Byte 00 :				Report ID = 0x12
	// Byte 01 : <-------------------------->  Btn3  Btn2  Btn1
	// Byte 02 :					 MSB X
	// Byte 03 :					 LSB X
	// Byte 04 :					 MSB Y
	// Byte 05 :					 LSB Y
	// Byte 06 :				  Delta Wheel
	// Btn3(MK_MBUTTON), Btn2(MK_RBUTTON), Btn1(MK_LBUTTON)
	//////////////////////////////////////////////////////////////
	0x05, 0x01, 						// USAGE_PAGE (Generic Desktop)
	0x09, 0x02, 						// USAGE (Mouse)
	0xa1, 0x01, 						// COLLECTION (Application)
	0x85, REPORTID_ABSMOUSE,			//	 REPORT_ID (Absolute Mouse)
	0x09, 0x01, 						//	 USAGE (Pointer)
	0xa1, 0x00, 						//	 COLLECTION (Physical)
	0x05, 0x09, 						//	   USAGE_PAGE (Button)
	0x19, 0x01, 						//	   USAGE_MINIMUM (Button 1)
	0x29, 0x03, 						//	   USAGE_MAXIMUM (Button 3)
	0x15, 0x00, 						//	   LOGICAL_MINIMUM (0)
	0x25, 0x01, 						//	   LOGICAL_MAXIMUM (1)
	0x75, 0x01, 						//	   REPORT_SIZE (1)
	0x95, 0x03, 						//	   REPORT_COUNT (3)
	0x81, 0x02, 						//	   INPUT (Data,Var,Abs)
	0x95, 0x05, 						//	   REPORT_COUNT (5)
	0x81, 0x03, 						//	   INPUT (Cnst,Var,Abs)
	0x05, 0x01, 						//	   USAGE_PAGE (Generic Desktop)
	0x09, 0x30, 						//	   USAGE (X)
	0x09, 0x31, 						//	   USAGE (Y)
	0x75, 0x10, 						//	   REPORT_SIZE (16)
	0x95, 0x02, 						//	   REPORT_COUNT (2)
	0x15, 0x00, 						//	   LOGICAL_MINIMUM (0)
	0x26, 0xff, 0x7f,					//	   LOGICAL_MAXIMUM (32767)
	0x81, 0x02, 						//	   INPUT (Data,Var,Abs)
	0x09, 0x38, 						//	   USAGE (WHEEL)
	0x75, 0x08, 						//	   REPORT_SIZE (8)
	0x95, 0x01, 						//	   REPORT_COUNT (1)
	0x15, 0x81, 						//	   LOGICAL_MINIMUM (-127)
	0x25, 0x7f, 						//	   LOGICAL_MAXIMUM (127)
	0x81, 0x06, 						//	   INPUT (Data,Var,Rel)

	0x95, 0x07,							//	   REPORT_COUNT (7)
	0x81, 0x03, 						//	   INPUT (Cnst,Var,Abs)

	0xc0,								//	 END_COLLECTION
	0xc0,								// END_COLLECTION
#endif	//USE_ABSMOUSE

#if	defined(USE_KEYBOARD)
	//////////////////////////////////////////////////////////////
	//			  bit7	bit6  bit5	bit4  bit3	bit2  bit1	bit0
	// OByte 00 :				 Report ID = 0x13
	// OByte 01 : RGui	RAlt  RSft	RCtl  LGui	LAlt  LSft	LCtl
	// OByte 02 :					  KeyID1
	// OByte 03 :					  KeyID2
	// OByte 04 :					  KeyID3
	// OByte 05 :					  KeyID4
	// OByte 06 :					  KeyID5
	// KeyID : RightArrow(0x4F), LeftArrow(0x50), DownArrow(0x51), UpArrow(0x52), ...
	// example :
	//	Key pressed
	//		_MouReport[0] = MOU_REPORT_ID_KBD;
	//		_MouReport[1] = 0x00;	/* Modifier Keys */
	//		_MouReport[2] = 0x51;	/* Keycode 1 */
	//		...
	//		USBD_MOU_SendReport(&g_UsbOtgDevice, _MouReport, MOU_IN_PACKET_SIZE);
	//		...
	//	Key released
	//		_MouReport[2] = 0x00;	/* Keycode 1 */
	//		USBD_MOU_SendReport(&g_UsbOtgDevice, _MouReport, MOU_IN_PACKET_SIZE);
	//////////////////////////////////////////////////////////////
	0x05, 0x01, 						// USAGE_PAGE (Generic Desktop)
	0x09, 0x06, 						// USAGE (Keyboard)
	0xA1, 0x01, 						// COLLECTION (Application)
	0x85, REPORTID_KEYBOARD,			//	 REPORT_ID (Keyboard)
	0x05, 0x07, 						//	 USAGE (Key Codes)
	0x19, 0xE0, 						//	 USAGE_MINIMUM (224)
	0x29, 0xE7, 						//	 USAGE_MAXIMUM (231)
	0x15, 0x00, 						//	 LOGICAL_MINIMUM (0)
	0x25, 0x01, 						//	 LOGICAL_MAXIMUM (1)
	0x75, 0x01, 						//	 REPORT_SIZE (1)
	0x95, 0x08, 						//	 REPORT_COUNT (8)
	0x81, 0x02, 						//	 INPUT (Data,Variable,Absolute)
	0x95, 0x05, 						//	 REP6ORT_COUNT (5)
	0x75, 0x08, 						//	 REPORT_SIZE (8)
	0x15, 0x00, 						//	 LOGICAL_MINIMUM (0)
	0x25, 0x65, 						//	 LOGICAL_MAXIMUM (101)
	0x05, 0x07, 						//	 USAGE (Key Codes)
	0x19, 0x00, 						//	 USAGE_MINIMUM (0)
	0x29, 0x65, 						//	 USAGE_MAXIMUM (101)
	0x81, 0x00, 						//	 INPUT (Data,Array)

	0x95, 0x07,							//	   REPORT_COUNT (7)
	0x81, 0x03, 						//	 INPUT (Cnst,Var,Abs)

	0xC0,								// END_COLLECTION
#endif	//USE_KEYBOARD

#if	defined(USE_MULTITOUCH)
	0x05, 0x0d, 						// USAGE_PAGE (Digitizers)
	0x09, 0x04, 						// USAGE (Touch Screen)
	0xa1, 0x01, 						// COLLECTION (Application)
	0x85, REPORTID_MULTITOUCH,				//	 REPORT_ID (Touch)
	0x09, 0x22, 						//	 USAGE (Finger)
	MULTITOUCH_COLLECTION
	MULTITOUCH_COLLECTION
#if	(INPUT_MT_MAX_NUM > 2)
	MULTITOUCH_COLLECTION
	MULTITOUCH_COLLECTION
#endif
	0x05, 0x0d, 						//	 USAGE_PAGE (Digitizers)
	0x09, 0x54, 						//	 USAGE (Actual count)
	0x95, 0x01, 						//	 REPORT_COUNT (1)
	0x75, 0x08, 						//	 REPORT_SIZE (8)
	0x81, 0x02, 						//	 INPUT (Data,Var,Abs)
	0x85, REPORTID_MAXCOUNT,			//	 REPORT_ID (Feature)
	0x09, 0x55, 						//	 USAGE(Maximum Count)
	0x25, INPUT_MT_MAX_NUM, 			//	 LOGICAL_MAXIMUM (2)
	0xb1, 0x02, 						//	 FEATURE (Data,Var,Abs)
	0xc0,								// END_COLLECTION
	0x09, 0x0E, 						// USAGE (Configuration)
	0xa1, 0x01, 						// COLLECTION (Application)
	0x85, REPORTID_FEATURE, 			//	 REPORT_ID (Feature)
	0x09, 0x22, 						//	 USAGE (Finger)
	0xa1, 0x00, 						//	 COLLECTION (physical)
	0x09, 0x52, 						//	   USAGE (Input Mode)
	0x09, 0x53, 						//	   USAGE (Device Index)
	0x15, 0x00, 						//	   LOGICAL_MINIMUM (0)
	0x25, 0x0a, 						//	   LOGICAL_MAXIMUM (10)
	0x75, 0x08, 						//	   REPORT_SIZE (8)
	0x95, 0x02, 						//	   REPORT_COUNT (2)
	0xb1, 0x02, 						//	   FEATURE (Data,Var,Abs)
	0xc0,								//	 END_COLLECTION
	0xc0,								// END_COLLECTION
#endif	//USE_MULTITOUCH
};
static uint8_t ReportDesc_Hid[] =
{
	//////////////////////////////////////////////////////////////
	//           bit7  bit6  bit5  bit4  bit3  bit2  bit1  bit0
	// Byte 00 :                 Report ID = 0x21
	// Byte 01 :                      Data
	//                                 ...
	// Byte 63 :                      Data
	//////////////////////////////////////////////////////////////
	0x06, 0xFF, 0x00,				// USAGE_PAGE (Vendor Page: 0xFF00)
	0x09, 0x01,						// USAGE (Demo Kit)
	0xA1, 0x01,						// COLLECTION (Application)
	0x15, 0x00, 					//   LOGICAL_MINIMUM (0)
	0x26, 0xFF, 0x00,				//   LOGICAL_MAXIMUM (255)
	0x75, 0x08, 					//   REPORT_SIZE (8)
	0x85, REPORTID_HID,				//+  REPORT_ID
	0x95, HID_IN_PACKET_SIZE-1,		//   REPORT_COUNT ()
	0x09, 0x01, 					//   USAGE ID
	0x81, 0x00, 					//-  INPUT (Data,Array)
	0x09, 0x02, 					//   USAGE ID
	0x91, 0x00, 					//-  OUTPUT (Data,Array)
	0xC0,							// END_COLLECTION
};


/* USB HID device Configuration Descriptor */
static uint8_t USBD_HID_CfgDesc[] =
{
	0x09,	/* bLength: Configuration Descriptor size */
	USB_CONFIGURATION_DESCRIPTOR_TYPE,	/* bDescriptorType: Configuration */
/**/0x00,	/* wTotalLength: Bytes returned */
	0x00,
	USBD_ITF_MAX_NUM,	/* bNumInterfaces: 1 interface */
	0x01,	/* bConfigurationValue: Configuration value */
	USBD_IDX_CONFIG_STR,	/* iConfiguration: Index of string descriptor describing the configuration */
/**/0xE0,	/* bmAttributes: bus powered and Support Remote Wake-up */
	0x32,	/* MaxPower 100 mA: this current is used for detecting Vbus */

/************** Descriptor of INPUT interface ****************/
	0x09,	/* bLength: Interface Descriptor size */
	USB_INTERFACE_DESCRIPTOR_TYPE,	/* bDescriptorType: Interface descriptor type */
	INPUT_INTERFACE_NUMBER,	/* bInterfaceNumber: Number of Interface */
	0x00,	/* bAlternateSetting: Alternate setting */
	INPUT_NUM_ENDPOINTS,	/* bNumEndpoints */
	0x03,	/* bInterfaceClass: HID */
	0x01,	/* bInterfaceSubClass : 1=BOOT, 0=no boot */
	0x02,	/* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
	USB_INTERFACE_STRING_INPUT,	/* iInterface: Index of string descriptor */
	/******************** Descriptor of MOU report ********************/
	0x09,	/* bLength: HID Descriptor size */
	USBD_HID_DESCRIPTOR_TYPE,	/* bDescriptorType: HID */
	0x11,	/* bcdHID: HID Class Spec release number */
	0x01,
	0x00,	/* bCountryCode: Hardware target country */
	0x01,	/* bNumDescriptors: Number of HID class descriptors to follow */
	USBD_HID_REPORT_DESC,	/* bDescriptorType */
	LOBYTE(_countof(ReportDesc_Input)),	/* wItemLength: Total length of Report descriptor */
	HIBYTE(_countof(ReportDesc_Input)),
	/******************** Descriptor of MOU endpoint ********************/
	0x07,	/* bLength: Endpoint Descriptor size */
	USB_ENDPOINT_DESCRIPTOR_TYPE,	/* bDescriptorType: */
	INPUT_IN_EP,	/* bEndpointAddress: Endpoint Address (IN) */
	0x03,	/* bmAttributes: Interrupt endpoint */
	INPUT_IN_PACKET_SIZE, /* wMaxPacketSize: 4 Byte max */
	0x00,
	INPUT_INTERVAL,	/* bInterval: Polling Interval (10 ms) */
/************** Descriptor of INPUT interface ****************/

/************** Descriptor of HID interface ****************/
	0x09,	/* bLength: Interface Descriptor size */
	USB_INTERFACE_DESCRIPTOR_TYPE,	/* bDescriptorType: Interface descriptor type */
	HID_INTERFACE_NUMBER,	/* bInterfaceNumber: Number of Interface */
	0x00,	/* bAlternateSetting: Alternate setting */
	HID_NUM_ENDPOINTS,	/* bNumEndpoints */
	0x03,	/* bInterfaceClass: HID */
	0x00,	/* bInterfaceSubClass : 1=BOOT, 0=no boot */
	0x00,	/* nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse */
	USB_INTERFACE_STRING_HID,	/* iInterface: Index of string descriptor */
	/******************** Descriptor of HID report ********************/
	0x09,	/* bLength: HID Descriptor size */
	USBD_HID_DESCRIPTOR_TYPE,	/* bDescriptorType: HID */
	0x11,	/* bcdHID: HID Class Spec release number */
	0x01,
	0x00,	/* bCountryCode: Hardware target country */
	0x01,	/* bNumDescriptors: Number of HID class descriptors to follow */
	USBD_HID_REPORT_DESC,	/* bDescriptorType */
	LOBYTE(_countof(ReportDesc_Hid)),	/* wItemLength: Total length of Report descriptor */
	HIBYTE(_countof(ReportDesc_Hid)),
	/******************** Descriptor of HID endpoint ********************/
	0x07,	/* bLength: Endpoint Descriptor size */
	USB_ENDPOINT_DESCRIPTOR_TYPE,	/* bDescriptorType: */
	HID_IN_EP,	/* bEndpointAddress: Endpoint Address (IN) */
	0x03,	/* bmAttributes: Interrupt endpoint */
	HID_IN_PACKET_SIZE, /* wMaxPacketSize: 4 Byte max */
	0x00,
	HID_INTERVAL,	/* bInterval: Polling Interval (10 ms) */
	0x07,	/* bLength: Endpoint Descriptor size */
	USB_ENDPOINT_DESCRIPTOR_TYPE,	/* bDescriptorType: */
	HID_OUT_EP, /* bEndpointAddress: Endpoint Address (IN)*/
	0x03,	/* bmAttributes: Interrupt endpoint */
	HID_OUT_PACKET_SIZE,	/* wMaxPacketSize: 4 Byte max */
	0x00,
	HID_INTERVAL,	/* bInterval: Polling Interval (10 ms) */
/************** Descriptor of HID interface ****************/
};


/**
* @brief  USBD_HID_Init
*         Initialize the HID interface
* @param  pdev: device instance
* @param  cfgidx: Configuration index
* @retval status
*/
static uint8_t USBD_HID_Init(void *pdev, uint8_t cfgidx)
{
	DCD_EP_Open(pdev, INPUT_IN_EP, INPUT_IN_PACKET_SIZE, USB_OTG_EP_INT);

	DCD_EP_Open(pdev, HID_IN_EP, HID_IN_PACKET_SIZE, USB_OTG_EP_INT);
	DCD_EP_Open(pdev, HID_OUT_EP, HID_OUT_PACKET_SIZE, USB_OTG_EP_INT);
	DCD_EP_PrepareRx(pdev, HID_OUT_EP, HID_RxBuffer, HID_OUT_PACKET_SIZE);

	return USBD_OK;
}

/**
* @brief  USBD_HID_Init
*         DeInitialize the HID layer
* @param  pdev: device instance
* @param  cfgidx: Configuration index
* @retval status
*/
static uint8_t USBD_HID_DeInit(void *pdev, uint8_t cfgidx)
{
	DCD_EP_Close(pdev, INPUT_IN_EP);

	DCD_EP_Close(pdev, HID_IN_EP);
	DCD_EP_Close(pdev, HID_OUT_EP);

	return USBD_OK;
}

/**
* @brief  USBD_HID_Setup
*         Handle the HID specific requests
* @param  pdev: instance
* @param  req: usb requests
* @retval status
*/
static uint8_t USBD_HID_Setup(void *pdev, USB_SETUP_REQ *req)
{
	static uint32_t USBD_HID_AltSet = 0;
	static uint32_t USBD_HID_Protocol = 0;
	static uint32_t USBD_HID_IdleState = 0;
	uint16_t len = 0;
	uint8_t *pbuf = NULL;

	switch (req->bmRequest & USB_REQ_TYPE_MASK)
	{
	case USB_REQ_TYPE_CLASS:
		switch (req->bRequest)
		{
		case USBD_HID_REQ_SET_PROTOCOL:
			#if	DBG_MSG_HID
			printf("HID_REQ_SET_PROTOCOL : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			#endif	//DBG_MSG_HID
			USBD_HID_Protocol = (uint8_t)(req->wValue);
			break;

		case USBD_HID_REQ_GET_PROTOCOL:
			#if	DBG_MSG_HID
			printf("HID_REQ_GET_PROTOCOL : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			#endif	//DBG_MSG_HID
			USBD_CtlSendData(pdev, (uint8_t *)&USBD_HID_Protocol, 1);
			break;

		case USBD_HID_REQ_SET_IDLE:
			#if	DBG_MSG_HID
			printf("HID_REQ_SET_IDLE     : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			#endif	//DBG_MSG_HID
			USBD_HID_IdleState = (uint8_t)(req->wValue >> 8);
			break;

		case USBD_HID_REQ_GET_IDLE:
			#if	DBG_MSG_HID
			printf("HID_REQ_GET_IDLE     : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			#endif	//DBG_MSG_HID
			USBD_CtlSendData(pdev, (uint8_t *)&USBD_HID_IdleState, 1);
			break;

		case USBD_HID_REQ_SET_REPORT:
			printf("USBD_HID_REQ_SET_REPORT : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			{
				//u8 report_type = ((req->wValue >> 8) & 0xFF);	// 1(Input), 2(Output), 3(Feature)
				u8 report_id   = ((req->wValue >> 0) & 0xFF);
				switch (report_id)
				{
				case REPORTID_RELMOUSE:
					break;
				case REPORTID_ABSMOUSE:
					break;
				case REPORTID_KEYBOARD:
					break;
				case REPORTID_MULTITOUCH:
					break;
				case REPORTID_MAXCOUNT:
					break;
				case REPORTID_FEATURE:
					break;
				case REPORTID_HID:
					break;
				}
			}
			break;
		case USBD_HID_REQ_GET_REPORT:
			printf("USBD_HID_REQ_GET_REPORT : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			{
				//u8 report_type = ((req->wValue >> 8) & 0xFF);	// 1(Input), 2(Output), 3(Feature)
				u8 report_id   = ((req->wValue >> 0) & 0xFF);
				switch (report_id)
				{
				case REPORTID_RELMOUSE:
					break;
				case REPORTID_ABSMOUSE:
					break;
				case REPORTID_KEYBOARD:
					break;
				case REPORTID_MULTITOUCH:
					break;
				case REPORTID_MAXCOUNT:
					{
						static u8 buf[2] = {REPORTID_MAXCOUNT, INPUT_MT_MAX_NUM};
						USBD_CtlSendData(pdev, buf, sizeof(buf));
					}
					break;
				case REPORTID_FEATURE:
					break;
				case REPORTID_HID:
					break;
				}
			}
			break;

		default:
			printf("USBD_HID_UNKNOWN      : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			#if	DBG_MSG_HID
			printf("HID_REQ_UNKNOWN      : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			#endif	//DBG_MSG_HID
			USBD_CtlError(pdev, req);
			return USBD_FAIL;
		}
		break;

	case USB_REQ_TYPE_STANDARD:
		switch (req->bRequest)
		{
		case USB_REQ_GET_DESCRIPTOR:
			#if	DBG_MSG_HID
			printf("USB_REQ_GET_DESCRIPTOR : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			#endif	//DBG_MSG_HID
			if (req->wValue >> 8 == USBD_HID_REPORT_DESC)
			{
				switch (req->wIndex)
				{
				case INPUT_INTERFACE_NUMBER:
					len = MIN(_countof(ReportDesc_Input), req->wLength);
					pbuf = ReportDesc_Input;
					break;
				case HID_INTERFACE_NUMBER:
					len = MIN(_countof(ReportDesc_Hid), req->wLength);
					pbuf = ReportDesc_Hid;
					break;
				}
			}
			else if (req->wValue >> 8 == USBD_HID_DESCRIPTOR_TYPE)
			{
				pbuf = USBD_HID_CfgDesc + 0x12;
				len = MIN(_countof(USBD_HID_CfgDesc), req->wLength);
			}
			USBD_CtlSendData(pdev, pbuf, len);
			break;

		case USB_REQ_GET_INTERFACE:
			#if	DBG_MSG_HID
			printf("USB_REQ_GET_INTERFACE  : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			#endif	//DBG_MSG_HID
			USBD_CtlSendData(pdev, (uint8_t *)&USBD_HID_AltSet, 1);
			break;

		case USB_REQ_SET_INTERFACE:
			#if	DBG_MSG_HID
			printf("USB_REQ_SET_INTERFACE  : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			#endif	//DBG_MSG_HID
			USBD_HID_AltSet = (uint8_t)(req->wValue);
			break;

		default:
			printf("USB_REQ_UNKNOWN      : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
				req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
			break;
		}
		break;

	default:
		printf("USB_REQ_TYPE_UNKNOWN      : 0x%02X, 0x%02X, 0x%04X, 0x%04X, 0x%04X\r\n",
			req->bmRequest, req->bRequest, req->wValue, req->wIndex, req->wLength);
		break;
	}

	return USBD_OK;
}

/**
* @brief  USBD_HID_DataIn
*         handle data IN Stage
* @param  pdev: device instance
* @param  epnum: endpoint index
* @retval status
*/
static uint8_t USBD_HID_DataIn(void *pdev, uint8_t epnum)
{
	/* Ensure that the FIFO is empty before a new transfer, this condition could 
	be caused by  a new transfer before the end of the previous transfer */
	switch (epnum)
	{
	case 1:
		DCD_EP_Flush(pdev, INPUT_IN_EP);
		break;
	case 2:
		DCD_EP_Flush(pdev, HID_IN_EP);
		if (USBD_HID_EndOfSend_cb)
			USBD_HID_EndOfSend_cb(epnum);
		break;
	}

	return USBD_OK;
}

static uint8_t USBD_HID_DataOut(void *pdev, uint8_t epnum)
{
	uint16_t USB_Rx_Cnt;

	/* Get the received data buffer and update the counter */
	USB_Rx_Cnt = ((USB_OTG_CORE_HANDLE *)pdev)->dev.out_ep[epnum].xfer_count;

	switch (epnum)
	{
	case 1:
		break;
	case 2:
		if (USBD_HID_GetReport_cb)
			USBD_HID_GetReport_cb(HID_RxBuffer, USB_Rx_Cnt);
		/* Prepare Out endpoint to receive next packet */
		DCD_EP_PrepareRx(pdev, HID_OUT_EP, HID_RxBuffer, HID_OUT_PACKET_SIZE);
		break;
	case 3:
		break;
	}

	return USBD_OK;
}

/**
* @brief  USBD_HID_GetCfgDesc
*         return configuration descriptor
* @param  speed : current device speed
* @param  length : pointer data length
* @retval pointer to descriptor buffer
*/
static uint8_t *USBD_HID_GetCfgDesc(uint8_t speed, uint16_t *length)
{
	if (0 == USBD_HID_CfgDesc[2])
		USBD_HID_CfgDesc[2] = _countof(USBD_HID_CfgDesc);

	*length = sizeof(USBD_HID_CfgDesc);
	return USBD_HID_CfgDesc;
}

/**
* @brief  SendReport_xxx
*         Send HID Report
* @param  pdev: device instance
* @param  buff: pointer to report
* @retval status
*/
uint8_t SendReport_Input(USB_OTG_CORE_HANDLE *pdev, uint8_t *report, uint16_t len)
{
	if (pdev->dev.device_status == USB_OTG_CONFIGURED)
	{
		DCD_EP_Tx(pdev, INPUT_IN_EP, report, len);
	}

	return USBD_OK;
}
uint8_t SendReport_Hid(USB_OTG_CORE_HANDLE *pdev, uint8_t *report, uint16_t len)
{
	if (pdev->dev.device_status == USB_OTG_CONFIGURED)
	{
		DCD_EP_Tx(pdev, HID_IN_EP, report, len);
	}

	return USBD_OK;
}

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
